package eerbaar.client.internal.ctr.operator.area;

import eerbaar.area.AreaFactory;
import eerbaar.area.IArea;
import eerbaar.area.SquareIterator;
import eerbaar.elements.IElement;
import eerbaar.elements.extension.ElementFactory;
import eerbaar.game.IGame;
import eerbaar.position.IPosition;
import eerbaar.position.PositionFactory;

public class ValueArea {

    private class PositionValue {
        IPosition p;
        double amount;
    }

    private final IArea valueArea;

    public ValueArea(IGame game) {

        int width = game.getArea().getWidth();
        int height = game.getArea().getHeight();

        this.valueArea = AreaFactory.createArea(width, height);
    }

    public void decrement(final int x, final int y, final int amount) {

        if (x < 0 || x > this.valueArea.getWidth()) {
            return;
        }
        if (y < 0 || y > this.valueArea.getHeight()) {
            return;
        }

        IValue value = getValueObject(x, y);
        value.setIfLessThan(amount);
    }

    public IPosition findHeighest(IPosition start, int radius) {

        PositionValue current = get(start.getX(), start.getY());
        PositionValue value = new PositionValue();
        value.amount = current.amount;

        IPosition position = null;

        for (int i = 1; i < radius + 2; i++) {

            position = searchRing(start, value, i);

            if (position != null) {
                break;
            }
        }

        return position;
    }

    private PositionValue get(final int x, final int y) {

        PositionValue result = new PositionValue();
        result.amount = 1000;

        if (x < 0 || x > this.valueArea.getWidth()) {
            return result;
        }
        if (y < 0 || y > this.valueArea.getHeight()) {
            return result;
        }

        result.amount = getValue(x, y);
        result.p = PositionFactory.createPosition(x, y);

        return result;
    }

    private double getValue(IElement e) {

        IValue value = e.getExtension(IValue.class);

        if (value == null) {
            value = new Value();
            e.installExtension(IValue.class, value);
        }

        return value.getValue();
    }

    private double getValue(final int x, final int y) {

        double result = 0;

        IPosition p = PositionFactory.createPosition(x, y);
        IElement[] array = this.valueArea.getElements(p);

        IElement v;
        if (array.length == 1) {
            v = array[0];
            result = getValue(v);
        }

        return result;
    }

    public IArea getValueArea() {
        return this.valueArea;
    }

    private IValue getValueObject(final int x, final int y) {

        IPosition p = PositionFactory.createPosition(x, y);
        IElement[] array = this.valueArea.getElements(p);

        IValue value;
        if (array.length == 0) {
            IElement e = ElementFactory.create("value", x, y);
            value = new Value();
            e.installExtension(IValue.class, value);
            this.valueArea.addElement(e);
        } else {
            IElement v = array[0];
            value = v.getExtension(IValue.class);
        }

        return value;
    }

    public void increment(final int x, final int y, final int amount) {

        if (x < 0 || x > this.valueArea.getWidth()) {
            return;
        }
        if (y < 0 || y > this.valueArea.getHeight()) {
            return;
        }

        IValue value = getValueObject(x, y);
        value.setIfGreaterThan(amount);
    }

    public void incrementArea(int x, final int y, int radius, int gradient,
            int pattern) {

        if (x < 0 || x > this.valueArea.getWidth()) {
            return;
        }
        if (y < 0 || y > this.valueArea.getHeight()) {
            return;
        }
        if (pattern < 0 || pattern > 3) {
            throw new java.lang.IllegalArgumentException();
        }

        IPosition center = PositionFactory.createPosition(x, y);
        SquareIterator iterator = new SquareIterator(center, radius, true);
        IPosition cursor;
        while ((cursor = iterator.next()) != null) {

            double distance = iterator.getDistance();

            double nValue;
            if (pattern == 0) {
                nValue = Operator.opLongRange(distance, gradient);
            } else if (pattern == 1) {
                nValue = Operator.opShortRange(distance, gradient);
            } else if (pattern == 2) {
                nValue = Operator.opAdjustableRange(distance, gradient);
            } else {
                nValue = Operator.opPositiveAndNegative(distance, gradient);
            }

            IValue value = getValueObject(cursor.getX(), cursor.getY());

            if (nValue > 0) {
                value.setIfGreaterThan(nValue);
            } else {
                value.setIfLessThan(nValue);
            }
        }
    }

    private IPosition searchRing(IPosition p, PositionValue v, int radius) {

        IPosition result = null;

        double lowest = v.amount;
        SquareIterator iterator = new SquareIterator(p, radius, false);
        IPosition cursor;
        while ((cursor = iterator.next()) != null) {

            PositionValue test = get(cursor.getX(), cursor.getY());

            if (test.amount > lowest) {
                lowest = test.amount;
                result = test.p;
            }
        }

        return result;
    }

    @Override
    public String toString() {

        return toString(9, 9);
    }

    public String toString(int MAX_X, int MAX_Y) {

        return "";

        // String s = "";
        //
        // DecimalFormat format = (DecimalFormat) NumberFormat.getInstance();
        // format.setMaximumFractionDigits(3);
        // format.setMinimumFractionDigits(3);
        // format.setMinimumIntegerDigits(3);
        //
        // for (int y = 0; y < MAX_Y + 1; y++) {
        // for (int x = 0; x < MAX_X + 1; x++) {
        // s += "[";
        // s += "" + x + "," + y;
        // String v = ", 000.000";
        // IPosition p = PositionFactory.createPosition(x, y);
        // IElement[] elements = this.valueArea.getElements(p);
        // for (IElement element : elements) {
        // IValue value = element.getExtension(IValue.class);
        // if (value != null) {
        // double d = value.getValue();
        // if (d >= 0) {
        // v = ", " + format.format(d);
        // } else {
        // v = "," + format.format(d);
        // }
        // }
        // }
        // s += v + "]  ";
        // }
        // s += "\n";
        // }
        //
        // return s;
    }

}
